﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Text.RegularExpressions;

using AdaptationProject.Forms;
using AdaptationProject.Utils;
using AdaptationProject.Properties;
using SharedTypes;
using System.Collections;

namespace AdaptationProject
{
    // Форма для отображения дерева параметров
    public partial class CmdParams : Form
    {
        public CmdParams()
        {
            InitializeComponent();

            comboBoxValueType.Items.AddRange(m_paramName.typeName);
            radioButtonParamKey_CheckedChanged(radioButtonParamKey, new EventArgs());
            ClearNameParamTBoxes();
        }

        public ParamName m_paramName = new ParamName();
        public IDictionary<int, LinkedParameter> m_cmdList = new Dictionary<int, LinkedParameter>();

        //-------------------------------------------------------
        ParamParser m_parser = new ParamParser();
        private string m_regExValue;
        private const string XmlExt   = ".xml";
        private const string ExeExt   = ".exe";
        private const string AnyFiles = ".*";
        private const int newNextY = 12;
        private int lastValueCtrlNumber = 0;
        private int lastPercentCtrlNumber = 0;
        private int lastButtonFilePathCtrlNumber = 0;
        private string m_adaptDefultAlgorithm = "AdaptGenericAlgorithm.dll";

        private const string percentName = "процентное значение";

        private string oldNameParam;
        private string lastFileName;

        // Установить параметры по умолчанию
        private void SetDefaultParamType()
        {
            radioButtonParamKey.Checked      = true;
            radioButtonParamPosition.Checked = false;
        }

        private void ClearHeader()
        {
            textBoxAlgName.Text = string.Empty;
            textBoxExePath.Text = string.Empty;
        }

        void ClearAllDinamicCtrl()
        {
            Control[] textBoxValues = panelScrolling.Controls.Find(textBoxValue.Name, false);
            foreach (Control values in textBoxValues)
            {
                values.Text = string.Empty;
            }
            Control[] textBoxPercentParams = panelScrolling.Controls.Find(textBoxPercentParam.Name, false);
            foreach (Control values in textBoxPercentParams)
            {
                values.Text = string.Empty;
            }
        }

        private void ClearNameParamTBoxes()
        {
            SetDefaultParamType();

            editParamName.Text      = string.Empty;
            textBoxDescription.Text = string.Empty;
            editShortName.Text      = string.Empty;
            textBoxDefaultValue.Text = string.Empty;

            comboBoxValueType.SelectedIndex = 0;
            nubOrderNum.Value = 0;
            textBoxConditionLink.Text = "";
            textBoxValueEnd.Text = "";
            textBoxSeparator.Text = "";
            editShortName.Text = "";

            ClearAllDinamicCtrl();
        }

        private void ClearNameParamTBoxes2()
        {
            SetDefaultParamType();

            editParamName.Text = string.Empty;
            textBoxDescription.Text = string.Empty;
            editShortName.Text = string.Empty;
            textBoxDefaultValue.Text = string.Empty;

            comboBoxValueType.SelectedIndex = 0;
            textBoxConditionLink.Text = "";
            textBoxValueEnd.Text = "";
            textBoxSeparator.Text = "";
            editShortName.Text = "";

            ClearAllDinamicCtrl();
        }

        // Утсановка по умолчанию ctrl-елементов параметра
        void SetDefaultCtrl()
        {
            int firstCtrl = 1;
            Control[] textBoxValues = panelScrolling.Controls.Find(textBoxValue.Name, false);
            for (int i = firstCtrl; i < textBoxValues.Length; ++i)
            {
                panelScrolling.Controls.Remove(textBoxValues[i]);
            }
            Control[] textBoxPercentParams = panelScrolling.Controls.Find(textBoxPercentParam.Name, false);
            for (int i = firstCtrl; i < textBoxPercentParams.Length; ++i)
            {
                panelScrolling.Controls.Remove(textBoxPercentParams[i]);
            }
            Control[] labelValueParams = panelScrolling.Controls.Find(labelValueParam.Name, false);
            for (int i = firstCtrl; i < labelValueParams.Length; ++i)
            {
                panelScrolling.Controls.Remove(labelValueParams[i]);
            }
            Control[] labelPercentParams = panelScrolling.Controls.Find(labelPercent.Name, false);
            for (int i = firstCtrl; i < labelPercentParams.Length; ++i)
            {
                panelScrolling.Controls.Remove(labelPercentParams[i]);
            }
            Control[] buttonFilePathParams = panelScrolling.Controls.Find(buttonFilePathParam.Name, false);
            for (int i = firstCtrl; i < buttonFilePathParams.Length; ++i)
            {
                panelScrolling.Controls.Remove(buttonFilePathParams[i]);
            }

            lastValueCtrlNumber = 0;
            lastPercentCtrlNumber = 0;
            lastButtonFilePathCtrlNumber = 0;

            UpdateCtrlPosition();
        }

        //Удалить ctrl-элементы
        void DeleteOneCtrl(int count)
        {
            for (int i = 0; i < count; ++i)
            {
                if (lastValueCtrlNumber == 0)
                {
                    return;
                }

                Control found = GetControlByTag(panelScrolling, textBoxValue.Name, lastValueCtrlNumber.ToString());
                panelScrolling.Controls.Remove(found);

                found = GetControlByTag(panelScrolling, textBoxPercentParam.Name, lastPercentCtrlNumber.ToString());
                panelScrolling.Controls.Remove(found);

                found = GetControlByTag(panelScrolling, labelValueParam.Name, lastPercentCtrlNumber.ToString());
                panelScrolling.Controls.Remove(found);

                found = GetControlByTag(panelScrolling, labelPercent.Name, lastPercentCtrlNumber.ToString());
                panelScrolling.Controls.Remove(found);

                found = GetControlByTag(panelScrolling, buttonFilePathParam.Name, lastButtonFilePathCtrlNumber.ToString());
                panelScrolling.Controls.Remove(found);

                --lastValueCtrlNumber;
                --lastPercentCtrlNumber;
                --lastButtonFilePathCtrlNumber;
            }
            
            UpdateCtrlPosition();
        }

        // Очитьстить дерево
        private void ClearTreeBoxNames()
        {
            treeView1.Nodes.Clear();
            treeViewDebug.Nodes.Clear();
        }

        // Получение индекса по имени параметра
        public int GetIndexByName(string name)
        {
            IList<int> keys = m_cmdList.Keys.ToList();

            for (int i = 0; i < keys.Count; ++i)
            {
                if (m_cmdList[keys[i]].parameter.IsParamKey)
                {
                    if (name == m_cmdList[keys[i]].parameter.Name)
                    {
                        return keys[i];
                    }
                }
                else
                {
                    if (name == m_cmdList[keys[i]].parameter.AcceptableValues[0].TextValues)
                    {
                        return keys[i];
                    }
                }
            }
            return -1;
        }

        // Обносление списка по имени выбраного параметра
        void UpdateListValue(string nodeName)
        {
            int index = GetIndexByName(nodeName);
            if (-1 == index)
            {
                return;
            }

            IList<AcceptableValue> values = m_cmdList[index].parameter.AcceptableValues;
            UpdateCountOfCtrlItems(values.Count);

            Control[] textBoxValues = panelScrolling.Controls.Find(textBoxValue.Name, false);
            Control[] textBoxPercentParams = panelScrolling.Controls.Find(textBoxPercentParam.Name, false);

            for (int i = 0; i < textBoxValues.Length; ++i)
            {
                textBoxValues[i].Text = values[i].TextValues;
                textBoxPercentParams[i].Text = values[i].Percent.ToString();
            }

            comboBoxValueType.SelectedIndex = m_cmdList[index].parameter.Type;
            editShortName.Text = m_cmdList[index].parameter.ShortDescription;
            textBoxConditionLink.Text = m_cmdList[index].parameter.ConditionLink;
            textBoxSeparator.Text = m_cmdList[index].parameter.Separator;
            textBoxDescription.Text = m_cmdList[index].parameter.Description;
            textBoxValueEnd.Text = m_cmdList[index].parameter.ValueEnd;
            textBoxDefaultValue.Text = m_cmdList[index].parameter.DefaultValue.ToString();
        }

        // Обновление дерева параметров
        void UpdateTree(int index)
        {
            nubOrderNum.Value = index;

            if (index >= m_cmdList.Count)
            {
                return;
            }

            if (!m_cmdList.ContainsKey(index))
            {
                UpdateTree(++index);
            }

            if (index >= m_cmdList.Count)
            {
                return;
            }

            if (m_cmdList[index].parameter.IsParamKey)
            {
                AddChildNode(m_cmdList[index].parentKey, m_cmdList[index].parameter.Name);
                //AddChildNodeDebug(m_cmdList[index].parentKey, index.ToString() + "," + m_cmdList[index].parentKey);
            }
            else
            {
                if (m_cmdList[index].parameter.AcceptableValues.Count != 0)
                {
                    AddChildNode(m_cmdList[index].parentKey, m_cmdList[index].parameter.AcceptableValues[0].TextValues);
                    //AddChildNodeDebug(m_cmdList[index].parentKey, index.ToString() + "," + m_cmdList[index].parentKey);
                }
                else
                {
                    AddChildNode(m_cmdList[index].parentKey, "NONE");
                    //AddChildNodeDebug(m_cmdList[index].parentKey, index.ToString() + "," + m_cmdList[index].parentKey);
                }
            }

            UpdateTree(++index);
        }

        void UpdateListNames(string algName)
        {
            nubOrderNum.Value = 0;
            ClearTreeBoxNames();
            //InitTreeView(algName);

            UpdateTree(0);
        }

        private bool CheckValidType()
        {
            int indexType = comboBoxValueType.SelectedIndex;
            if (indexType == -1)
            {
                string errorInfo = "Выберите пожалуйста тип параметра";
                toolStripStatusLabel1.Text = errorInfo;
                errorProvider.SetError(comboBoxValueType, errorInfo);
                MessageBox.Show("Тип параметра не выбрано", "Ошибка выбора типа параметра", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            else
            {
                errorProvider.SetError(comboBoxValueType, "");
                toolStripStatusLabel1.Text = "";
            }
            return true;
        }

        // Добавление значение параметра
        void AddAcceptValuesFromBoxed(out IList<AcceptableValue> acceptValues)
        {
            acceptValues = new List<AcceptableValue>();
            Control[] textBoxValues = panelScrolling.Controls.Find(textBoxValue.Name, false);
            Control[] textBoxPercentParams = panelScrolling.Controls.Find(textBoxPercentParam.Name, false);
            for (int i = 0; i < textBoxValues.Length; ++i)
            {
                AcceptableValue acceptValue = new AcceptableValue();
                acceptValue.values = m_parser.Parse(textBoxValue.Text, comboBoxValueType.SelectedIndex);
                acceptValue.TextValues = textBoxValues[i].Text;
                long boundary = 0;
                Int64.TryParse(textBoxPercentParams[i].Text, out boundary);
                acceptValue.Percent = boundary;
                acceptValues.Add(acceptValue);
            }
        }
        
        void ChangeEnabledButtonFilePath(bool isEnabled)
        {
            for (int i = 0; i <= lastButtonFilePathCtrlNumber; ++i)
            {
                Control prev = GetControlByTag(panelScrolling, buttonFilePathParam.Name, i.ToString());
                prev.Enabled = isEnabled;
            }
        }

        //----------------------------------------------------------------

        // Добавление имени параметра
        private void butAddName_Click(object sender, EventArgs e)
        {
            if (!CheckValidType())
            {
                return;
            }

            if (!Ckeck.CheckValidValue(textBoxValue.Text,
                                       m_regExValue,                       
                                       m_paramName.fullName[comboBoxValueType.SelectedIndex],
                                       textBoxValue,
                                       errorProvider,
                                       toolStripStatusLabel1))
            {
                MessageBox.Show("Неверное значение параметра", "Ошибка ввода значение параметра", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            IList<AcceptableValue> acceptValues;

            AddAcceptValuesFromBoxed(out acceptValues);
            
            CmdParameter cmdParam = new CmdParameter((byte)nubOrderNum.Value,
                                                     editParamName.Text,
                                                     textBoxConditionLink.Text,
                                                     editShortName.Text,
                                                     textBoxDescription.Text,
                                                     acceptValues,
                                                     textBoxValueEnd.Text,
                                                     textBoxSeparator.Text,
                                                     textBoxDefaultValue.Text,
                                                     radioButtonParamKey.Checked,
                                                     comboBoxValueType.SelectedIndex);

            int parentIndex = -1;
            if (null != treeView1.SelectedNode)
            {
                parentIndex = treeView1.SelectedNode.SelectedImageIndex == -1 ? 0 : treeView1.SelectedNode.SelectedImageIndex;
            }

//             if (m_cmdList.Count == 0)
//             {
//                 InitTreeView(textBoxAlgName.Text);
//             }

            m_cmdList.Add((int)nubOrderNum.Value, new LinkedParameter(parentIndex, cmdParam));

            // Если ключевой параметр
            if (cmdParam.IsParamKey)
            {
                AddChildNode(parentIndex, cmdParam.Name);
                //AddChildNodeDebug(parentIndex, ((int)nubOrderNum.Value).ToString() + "," + parentIndex.ToString());
            } 
            else
            {
                AddChildNode(parentIndex, textBoxValue.Text);
                //AddChildNodeDebug(parentIndex, ((int)nubOrderNum.Value).ToString() + "," + parentIndex.ToString());
            }
            nubOrderNum.Value++;
            //globalIndex++;

//             int oldSelectedItem = listBoxNameParam.SelectedIndex;
// 
//             if (listBoxNameParam.SelectedIndex == -1)
//             {
//                 listBoxNameParam.SelectedIndex = oldSelectedItem == -1 ? 0 : oldSelectedItem;
//             }

            ClearNameParamTBoxes2();
            SetDefaultCtrl();
        }

        private void butChangeValue_Click(object sender, EventArgs e)
        {
            int indexName = treeView1.SelectedImageIndex;
            if (indexName == -1)
            {
                MessageBox.Show("Имя параметра не выбрано", "Ошибка выбора имени параметра", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            IParameter tmpInfo = m_cmdList[indexName].parameter;

            IList<AcceptableValue> acceptValues;

            AddAcceptValuesFromBoxed(out acceptValues);

            CmdParameter newParam = new CmdParameter(tmpInfo.OrderNum,
                                                     tmpInfo.Name,
                                                     tmpInfo.ConditionLink,
                                                     tmpInfo.ShortDescription,
                                                     tmpInfo.Description,
                                                     acceptValues,
                                                     tmpInfo.ValueEnd,
                                                     tmpInfo.Separator,
                                                     tmpInfo.DefaultValue,
                                                     tmpInfo.IsParamKey,
                                                     comboBoxValueType.SelectedIndex);
            m_cmdList[indexName].parameter = newParam;
        }

        // Редактирование параметра
        private void butChangeName_Click(object sender, EventArgs e)
        {
            if (!CheckValidType())
            {
                return;
            }

            if (!Ckeck.CheckValidValue(textBoxValue.Text,
                                       m_regExValue,                       
                                       m_paramName.fullName[comboBoxValueType.SelectedIndex],
                                       textBoxValue,
                                       errorProvider,
                                       toolStripStatusLabel1))
            {
                MessageBox.Show("Неверное значение параметра", "Ошибка ввода значение параметра", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (null == treeView1.SelectedNode)
            {
                MessageBox.Show("Имя параметра не найдено", "Ошибка поиск имение параметра", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            IList<AcceptableValue> acceptValues;

            AddAcceptValuesFromBoxed(out acceptValues);

            int indexName = GetIndexByName(treeView1.SelectedNode.Text);

            CmdParameter cmdParam = new CmdParameter(m_cmdList[indexName].parameter.OrderNum,
                                                     editParamName.Text,
                                                     textBoxConditionLink.Text,
                                                     editShortName.Text,
                                                     textBoxDescription.Text,
                                                     acceptValues,
                                                     textBoxValueEnd.Text,
                                                     textBoxSeparator.Text,
                                                     textBoxDefaultValue.Text,
                                                     radioButtonParamKey.Checked,
                                                     comboBoxValueType.SelectedIndex);

            m_cmdList[indexName].parameter = cmdParam;

            UpdateListNames(textBoxAlgName.Text);
            UpdateListValue(cmdParam.Name);
        }

        // Уменьшение id linked параметра, если один был удален
        void DecSubLinked(ArrayList keys, int indexName, int subItems)
        {
            for (int i = 0; i < keys.Count - 1; ++i)
            {
                if (m_cmdList[(int)keys[i]].parentKey == indexName)
                {
                    m_cmdList[(int)keys[i]].parentKey -= subItems;
                }
            }
        }
        // Понижение номера после удаления
        void DecOtherParam(int indexName, int countDeleted)
        {
            ArrayList keys = new ArrayList(m_cmdList.Keys.ToList());
            keys.Sort();

            for (int i = 0; i < keys.Count-1; ++i)
            {
                if ((int)keys[i+1] - (int)keys[i] > 1)
                {
                    LinkedParameter tmp = m_cmdList[(int)keys[i+1]];
                    int numKey = (int)keys[i+1];
                    m_cmdList.Remove((int)keys[i+1]);
                    int subKeys = (int)keys[i+1] - (int)keys[i]-1;
                    m_cmdList.Add(numKey - subKeys, tmp);

                    keys = new ArrayList(m_cmdList.Keys.ToList());
                    keys.Sort();
                    --i;
                    DecSubLinked(keys, numKey, subKeys);
                }
            }
        }

        // Удаление все слинкованых параметров
        void RemoveAllLinkedParam(int indexName)
        {
            int countDeleted = 0; 
            if (m_cmdList.Remove(indexName))
            {
                countDeleted = 1;// один удален (главный)
            }

            IList<int> keys = m_cmdList.Keys.ToList();
            for (int i = 0; i < keys.Count; ++i)
            {
                if (indexName == m_cmdList[keys[i]].parentKey)
                {
                    m_cmdList.Remove(keys[i]);
                    ++countDeleted;
                }
            }
            DecOtherParam(indexName, countDeleted);
        }
        
        // Удаление параметра
        private void butDeleteName_Click(object sender, EventArgs e)
        {
            if (null == treeView1.SelectedNode)
            {
                MessageBox.Show("Значение не выбрано", "Ошибка выбора имени параметра", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            
            string questingText = string.Format("Вы действительно хотите удалить параметр: {0}, со всеми его значениями?",
                                                treeView1.SelectedNode.Text);

            if (MessageBox.Show(questingText, "Предупреждение", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
            {
                return;
            }
            int indexName = GetIndexByName(treeView1.SelectedNode.Text);
            RemoveAllLinkedParam(indexName);

            UpdateListNames(textBoxAlgName.Text);

            if (treeView1.Nodes.Count == 0)
            {
                return;
            }
            if (treeView1.Nodes.Count > indexName)
            {
                treeView1.SelectedImageIndex = indexName;
            }
            else
            {
                treeView1.SelectedImageIndex = treeView1.Nodes.Count - 1;
            }
        }

        // Обрабока значение параметра
        private void editValueParam_KeyUp(object sender, KeyEventArgs e)
        {
            Regex regex = new Regex(m_regExValue);

            Control ctrl = (Control)sender;

            Ckeck.CheckValidValue(ctrl.Text,
                                  m_regExValue,
                                  m_paramName.fullName[comboBoxValueType.SelectedIndex],
                                  ctrl,
                                  errorProvider,
                                  toolStripStatusLabel1);
        }

        // Выбор типа параметра
        private void comboBoxValueType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxValueType.SelectedIndex != ParamType.FILE)
            {
                ChangeEnabledButtonFilePath(false);
            }

            switch (comboBoxValueType.SelectedIndex)
            {
                case ParamType.STRING:
                case ParamType.FILENAME:
                    m_regExValue = ParamType.regExString;
                    break;

                case ParamType.INT:
                    m_regExValue = ParamType.regExInteger;
                    break;

                case ParamType.FLOAT:
                    m_regExValue = ParamType.regExFloat;
                    break;

                case ParamType.SYMBOL:
                    m_regExValue = ParamType.regExSymbol;
                    break;

                case ParamType.FILE:
                case ParamType.HELPFILE:
                    m_regExValue = ParamType.regExFile;
                    ChangeEnabledButtonFilePath(true);
                    break;

                case ParamType.HANDLE:
                    m_regExValue = ParamType.regExHandle;
                    break;

                case ParamType.PATH:
                    m_regExValue = ParamType.regExPath;
                    ChangeEnabledButtonFilePath(true);
                    break;

                case ParamType.UNKNOWN:
                default:
                    MessageBox.Show("Выбран неверный тип параметра!\nПовторите еще раз",
                                    "Ошибка в выборе типа параметра",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    break;
            }
        }

        private void radioButtonParamKey_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton ctrl = (RadioButton)sender;
            if (ctrl.Checked)
            {
                editParamName.ReadOnly = false;
                editParamName.Enabled = true;
            }
        }

        private void radioButtonParamPosition_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton ctrl = (RadioButton)sender;
            if (ctrl.Checked)
            {
                editParamName.ReadOnly = true;
                editParamName.Enabled = false;
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Все несохраненные данные будут утеряны!\nВы действительно хотите выйти?", "Вопрос", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                this.Close();
            }
        }

        public void LoadInfo(string fileName)
        {
            XMLParamParser parsers = new XMLParamParser();
            parsers.Load(fileName);
            lastFileName = fileName;

            try
            {
                m_cmdList = parsers.GetAlgorithmParameters();
            }
            catch(Exception exp)
            {
                MessageBox.Show("Файл содержит неверный формат задания параметров",
                                "Ошибка в содержимом файла",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                return;
            }
            UpdateListNames(parsers.GetAlgorithmName());
            treeView1.Refresh();
            UpdateListValue(treeView1.Nodes[0].Text);
            textBoxAlgName.Text = parsers.GetAlgorithmName();
            textBoxExePath.Text = parsers.GetExePath();
        }

        // Открытие дерева парамтеров
        private void openFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                dlg.CheckFileExists = true;
                dlg.CheckPathExists = true;
                dlg.ValidateNames = true;
                dlg.DefaultExt = XmlExt;
                dlg.Filter = "XML files (*" + XmlExt + ")|*" + XmlExt;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    if (dlg.SafeFileName.EndsWith(XmlExt))
                    {
                        try
                        {
                            LoadInfo(dlg.FileName);
                            lastFileName = dlg.FileName;
                        }
                        catch (IOException exception)
                        {
                            MessageBox.Show(exception.Message);
                        }
                    }
                    else
                    {
                        MessageBox.Show(Resources.MAIN_InvalidFileExtText, Resources.MAIN_InvalidFileExtTitle,
                                        MessageBoxButtons.OK);
                    }
                }
            }
        }

        private void ClearAll()
        {
            ClearNameParamTBoxes();
            ClearTreeBoxNames();
            ClearHeader();
        }

        private void saveToFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lastFileName != null && lastFileName != "")
            {
                SaveParams(lastFileName, false);
            }
        }

        string GetFilePath(string description, string extension)
        {
            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                dlg.CheckFileExists = true;
                dlg.CheckPathExists = true;
                dlg.ValidateNames = true;
                dlg.DefaultExt = extension;
                dlg.Filter = description + " files (*" + extension + ")|*" + extension;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    if (extension == ".*" || dlg.SafeFileName.EndsWith(extension))
                    {
                        try
                        {
                            return dlg.FileName;
                        }
                        catch (IOException exception)
                        {
                            MessageBox.Show(exception.Message);
                        }
                    }
                    else
                    {
                        MessageBox.Show("Расширение файла должно быть " + extension,
                        Resources.ADDALGDescr_InvalidLibraryExtTitle, MessageBoxButtons.OK);
                    }
                }
            }
            return "";
        }

        string GetFolderPath()
        {
            using (FolderBrowserDialog dlg = new FolderBrowserDialog())
            {
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    return dlg.SelectedPath;
                }
            }
            return "";
        }

        private void buttonExePath_Click(object sender, EventArgs e)
        {
            string newFilePath = GetFilePath("exe", ExeExt);
            textBoxExePath.Text = newFilePath != "" ? newFilePath : textBoxExePath.Text;
        }

        private void buttonClearAllBoxes_Click(object sender, EventArgs e)
        {
            ClearNameParamTBoxes();
        }

        private void buttonClearListParams_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Все несохраненные данные бедет утеряны!\nВы действительно очистить список параметров?",
                                                  "Вопрос",
                                                  MessageBoxButtons.YesNo,
                                                  MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                ClearAll();
            }
        }

        private void buttonFilePathParam_Click(object sender, EventArgs e)
        {
            switch (comboBoxValueType.SelectedIndex)
            {
                case ParamType.FILE:
                case ParamType.HELPFILE:
                    {
                        string filePath = GetFilePath("Any", AnyFiles);
                        Button ctrl = (Button)sender;
                        Control found = GetControlByTag(panelScrolling, textBoxValue.Name, ctrl.Tag.ToString());
                        found.Text = filePath.Length != 0 ? filePath : textBoxValue.Text;
                    }
                    break;
                case ParamType.PATH:
                    {
                        string filePath = GetFolderPath();
                        Button ctrl = (Button)sender;
                        Control found = GetControlByTag(panelScrolling, textBoxValue.Name, ctrl.Tag.ToString());
                        found.Text = filePath.Length != 0 ? filePath : textBoxValue.Text;
                    }
                    break;
            }
        }

        private void textBoxPercentParam_KeyUp(object sender, KeyEventArgs e)
        {
            Regex regex = new Regex(ParamType.regExPercent);

            Control ctrl = (Control)sender;

            Ckeck.CheckValidValue(ctrl.Text,
                                  ParamType.regExPercent,
                                  percentName,
                                  ctrl,
                                  errorProvider,
                                  toolStripStatusLabel1);
        }

        Control GetControlByTag(Panel panel, string paramName, string tag)
        {
            foreach (Control c in panel.Controls)
            {
                if (c.Tag != null &&
                    c.Name == paramName &&
                    c.Tag.ToString() == tag)
                {
                    return c;
                }
            }
            
            return null;
        }

        // Добавление ctrl элемента
        private void AddValueTextBoxCtrl()
        {
            TextBox nextTextBoxValue = new TextBox();
            nextTextBoxValue.Text    = "";
            nextTextBoxValue.Tag     = (lastValueCtrlNumber + 1);
            nextTextBoxValue.Name    = textBoxValue.Name;

            Control last = GetControlByTag(panelScrolling, textBoxValue.Name, lastValueCtrlNumber.ToString());
            
            int x1     = last.Location.X;
            int y1     = last.Location.Y;
            int height = last.Height;
            int width  = last.Width;

            nextTextBoxValue.Location = new System.Drawing.Point(x1, y1 + height + newNextY);
            nextTextBoxValue.Height   = last.Height;
            nextTextBoxValue.Width    = last.Width;

            panelScrolling.Controls.Add(nextTextBoxValue);

            nextTextBoxValue.KeyUp += new System.Windows.Forms.KeyEventHandler(this.editValueParam_KeyUp);

            ++lastValueCtrlNumber;
        }

        // Добавление ctrl элемента
        private void AddValueLabelCtrl()
        {
            Label nextLabelValueParam = new Label();
            nextLabelValueParam.Text  = labelValueParam.Text;
            nextLabelValueParam.Name  = labelValueParam.Name;
            nextLabelValueParam.Tag   = lastValueCtrlNumber.ToString();

            Control last = GetControlByTag(panelScrolling, textBoxValue.Name, lastValueCtrlNumber.ToString());
            
            int x1 = last.Location.X;
            int y1 = last.Location.Y;

            nextLabelValueParam.Location = new System.Drawing.Point(labelValueParam.Location.X, y1 + 2);
            nextLabelValueParam.Height   = labelValueParam.Height;
            nextLabelValueParam.Width    = labelValueParam.Width;

            panelScrolling.Controls.Add(nextLabelValueParam);
        }

        // Добавление ctrl элемента
        private void AddPercentTextBoxCtrl()
        {
            TextBox nextTextBoxPercentParam = new TextBox();
            nextTextBoxPercentParam.Text = "";
            nextTextBoxPercentParam.Tag  = (lastPercentCtrlNumber + 1);
            nextTextBoxPercentParam.Name = textBoxPercentParam.Name;

            Control last = GetControlByTag(panelScrolling, textBoxPercentParam.Name, lastPercentCtrlNumber.ToString());
            
            int x1     = last.Location.X;
            int y1     = last.Location.Y;
            int height = last.Height;
            int width  = last.Width;

            nextTextBoxPercentParam.Location = new System.Drawing.Point(x1, y1 + height + newNextY);
            nextTextBoxPercentParam.Height   = last.Height;
            nextTextBoxPercentParam.Width    = last.Width;

            panelScrolling.Controls.Add(nextTextBoxPercentParam);

            nextTextBoxPercentParam.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxPercentParam_KeyUp);

            ++lastPercentCtrlNumber;
        }

        // Добавление ctrl элемента
        private void AddButtonFilePathCtrl()
        {
            Button nextButtonFilePathParam  = new Button();
            nextButtonFilePathParam.Text    = buttonFilePathParam.Text;
            nextButtonFilePathParam.Enabled = buttonFilePathParam.Enabled;
            nextButtonFilePathParam.Font    = buttonFilePathParam.Font;
            nextButtonFilePathParam.Tag     = (lastButtonFilePathCtrlNumber + 1);
            nextButtonFilePathParam.Name    = buttonFilePathParam.Name;

            Control last = GetControlByTag(panelScrolling, buttonFilePathParam.Name, lastButtonFilePathCtrlNumber.ToString());
            
            int x1     = last.Location.X;
            int y1     = last.Location.Y;
            int height = last.Height;
            int width  = last.Width;

            nextButtonFilePathParam.Location = new System.Drawing.Point(x1, y1 + height + newNextY);
            nextButtonFilePathParam.Height   = last.Height;
            nextButtonFilePathParam.Width    = last.Width;

            panelScrolling.Controls.Add(nextButtonFilePathParam);

            nextButtonFilePathParam.Click += new System.EventHandler(this.buttonFilePathParam_Click);

            ++lastButtonFilePathCtrlNumber;
        }

        // Добавление ctrl элемента
        private void AddPercentLabelCtrl()
        {
            Label nextLabelPercentParam = new Label();
            nextLabelPercentParam.Text  = labelPercent.Text;
            nextLabelPercentParam.Name  = labelPercent.Name;
            nextLabelPercentParam.Tag   = lastValueCtrlNumber.ToString();

            Control prev = GetControlByTag(panelScrolling, textBoxValue.Name, lastValueCtrlNumber.ToString());
            
            int x1 = prev.Location.X;
            int y1 = prev.Location.Y;

            nextLabelPercentParam.Location = new System.Drawing.Point(labelPercent.Location.X, y1 + 2);
            nextLabelPercentParam.Height   = labelPercent.Height;
            nextLabelPercentParam.Width    = labelPercent.Width;

            panelScrolling.Controls.Add(nextLabelPercentParam);
        }

        // Обновление ctrl элемента
        void UpdateCtrlPosition()
        {
            Control prev = GetControlByTag(panelScrolling, textBoxValue.Name, lastValueCtrlNumber.ToString());

            int x1 = prev.Location.X;
            int y1 = prev.Location.Y;

            buttonAddControl.Location = new System.Drawing.Point(buttonAddControl.Location.X,
                                                                 y1 + buttonAddControl.Height + newNextY);

            buttonRemoveControl.Location = new System.Drawing.Point(buttonRemoveControl.Location.X,
                                                                    y1 + buttonRemoveControl.Height + newNextY);

            textBoxValueEnd.Location = new System.Drawing.Point(x1,
                                                                buttonAddControl.Location.Y + buttonAddControl.Height + newNextY);

            label6.Location = new System.Drawing.Point(label6.Location.X, textBoxValueEnd.Location.Y);

            textBoxSeparator.Location = new System.Drawing.Point(x1,
                                                                 textBoxValueEnd.Location.Y + textBoxValueEnd.Height + newNextY);

            label8.Location = new System.Drawing.Point(label8.Location.X, textBoxSeparator.Location.Y);

            textBoxDefaultValue.Location = new System.Drawing.Point(x1,
                                                                    textBoxSeparator.Location.Y + textBoxSeparator.Height + newNextY);

            label5.Location = new System.Drawing.Point(label5.Location.X, textBoxDefaultValue.Location.Y);


            editShortName.Location = new System.Drawing.Point(editShortName.Location.X,
                                                              textBoxDefaultValue.Location.Y + textBoxDefaultValue.Height + newNextY);

            label4.Location = new System.Drawing.Point(label4.Location.X, editShortName.Location.Y);

            textBoxDescription.Location = new System.Drawing.Point(x1,
                                                                   editShortName.Location.Y + editShortName.Height + newNextY);

            x1 = textBoxDescription.Location.X;
            y1 = textBoxDescription.Location.Y;

            label3.Location = new System.Drawing.Point(label3.Location.X, y1);
        }

        void UpdateCountOfCtrlItems(int count)
        {
            Control[] textBoxValues = panelScrolling.Controls.Find(textBoxValue.Name, false);

            if (textBoxValues.Length < count)
            {
                count = count - textBoxValues.Length;
                AddCountOfCtrlItems(count);
            }
            else if (textBoxValues.Length > count)
            {
                count = textBoxValues.Length - count;
                DeleteOneCtrl(count);
            }
        }

        void AddCountOfCtrlItems(int count)
        {
            for (int i = 0; i < count; ++i)
            {
                AddValueTextBoxCtrl();
                AddValueLabelCtrl();
                AddPercentTextBoxCtrl();
                AddPercentLabelCtrl();
                AddButtonFilePathCtrl();
            }
            UpdateCtrlPosition();
        }

        private void buttonAddControl_Click(object sender, EventArgs e)
        {
            AddCountOfCtrlItems(1);
        }

        private void buttonRemoveControl_Click(object sender, EventArgs e)
        {
            DeleteOneCtrl(1);
        }

        private void InitTreeView(string algName)
        {
            if (treeView1.Nodes.Count == 0)
            {
                treeView1.Nodes.Add(algName);
                treeView1.SelectedNode = treeView1.Nodes[0];
            }
        }

        private TreeNode GetParentKeyByIndexChild(TreeNode treeNode, int parent)
        {
            foreach (TreeNode node in treeNode.Nodes)
            {
                if (node.SelectedImageIndex == parent)
                {
                    return node;
                }

                TreeNode result = GetParentKeyByIndexChild(node, parent);
                if (result != null)
                {
                    return result;
                }
            }

            return treeNode.SelectedImageIndex == parent ? treeNode : null;
        }

        private TreeNode GetParentKeyByIndex(int parent)
        {
            TreeNode result = null;

            foreach (TreeNode mainNode in treeView1.Nodes)
            {
                result = GetParentKeyByIndexChild(mainNode, parent);
                if (result != null)
                {
                    return result;
                }
            }
            
            return result;
        }

        private TreeNode GetParentKeyByIndexDebug(int parent)
        {
            TreeNode result = null;

            foreach (TreeNode mainNode in treeViewDebug.Nodes)
            {
                result = GetParentKeyByIndexChild(mainNode, parent);
                if (result != null)
                {
                    return result;
                }
            }

            return result;
        }

        private void AddChildNode(int parent, string str)
        {
            var childNodeName = str.Trim();
            if(string.IsNullOrEmpty(childNodeName))
            {
                return;
            }

            if (-1 == parent) // если самый верхний уровень
            {
                treeView1.Nodes.Add(str);
                treeView1.SelectedNode = treeView1.Nodes[0];
                treeView1.Nodes[treeView1.Nodes.Count - 1].SelectedImageIndex = (int)nubOrderNum.Value;
            }
            else
            {
                TreeNode parentNode = GetParentKeyByIndex(parent);
                if (parentNode != null)
                {
                    TreeNode node = new TreeNode(childNodeName);

                    parentNode.Nodes.Add(node);
                    parentNode.Nodes[parentNode.Nodes.IndexOf(node)].SelectedImageIndex = (int)nubOrderNum.Value;
                    treeView1.ExpandAll();
                }
            }
        }

        private void AddChildNode(string str)
        {
            var childNodeName = str.Trim();
            if (!string.IsNullOrEmpty(childNodeName))
            {
                TreeNode parentNode = treeView1.SelectedNode != null ? treeView1.SelectedNode : treeView1.Nodes[0];
                if (parentNode != null)
                {
                    TreeNode node = new TreeNode(childNodeName);

                    parentNode.Nodes.Add(node);
                    parentNode.Nodes[parentNode.Nodes.IndexOf(node)].SelectedImageIndex = (int)nubOrderNum.Value;
                    treeView1.ExpandAll();
                }
            }
        }

        private void AddChildNodeDebug(int parent, string str)
        {
            var childNodeName = str.Trim();
            if (-1 == parent) // если самый верхний уровень
            {
                treeViewDebug.Nodes.Add(str);
                treeViewDebug.SelectedNode = treeViewDebug.Nodes[0];
                treeViewDebug.Nodes[treeView1.Nodes.Count - 1].SelectedImageIndex = (int)nubOrderNum.Value;
            }
            else if (!string.IsNullOrEmpty(childNodeName))
            {
                TreeNode parentNode = GetParentKeyByIndexDebug(parent);
                if (parentNode != null)
                {
                    TreeNode node = new TreeNode(childNodeName);

                    parentNode.Nodes.Add(node);
                    parentNode.Nodes[parentNode.Nodes.IndexOf(node)].SelectedImageIndex = (int)nubOrderNum.Value;
                    treeViewDebug.ExpandAll();
                }
            }
        }

        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            // crutch
            UpdateListValue(e.Node.Text);

            int index = GetIndexByName(e.Node.Text);
            if (-1 == index)
            {
                return;
            }

            if (m_cmdList[index].parameter.IsParamKey)
            {
                radioButtonParamKey.Checked = true;
                radioButtonParamKey.Checked = true;
                radioButtonParamPosition.Checked = false;
                editParamName.Text = m_cmdList[index].parameter.Name;
            }
            else
            {
                radioButtonParamKey.Checked = false;
                radioButtonParamKey.Checked = false;
                radioButtonParamPosition.Checked = true;
                editParamName.Text = "";
            }

            int count = m_cmdList[index].parameter.AcceptableValues.Count - 1;
            lastValueCtrlNumber = count;
            lastPercentCtrlNumber = count;
            lastButtonFilePathCtrlNumber = count;

            oldNameParam = editParamName.Text;

        }

        void SaveParams(string fileName, bool isSaveAs)
        {
            try
            {
                XMLParamParser localParset = new XMLParamParser();
                localParset.CreateTemplateDocument(fileName);
                localParset.Load(fileName);
                localParset.SetHeader(textBoxAlgName.Text, m_adaptDefultAlgorithm, textBoxExePath.Text);

                foreach (KeyValuePair<int, LinkedParameter> info in m_cmdList)
                {
                    localParset.AddParameter(info.Value.parameter.OrderNum,
                                             info.Value.parentKey,
                                             info.Value.parameter.Name,
                                             info.Value.parameter.ConditionLink,
                                             info.Value.parameter.ShortDescription,
                                             info.Value.parameter.Description,
                                             info.Value.parameter.AcceptableValues,
                                             info.Value.parameter.ValueEnd,
                                             info.Value.parameter.Separator,
                                             info.Value.parameter.DefaultValue.ToString().Replace(',', '.'),
                                             info.Value.parameter.IsParamKey,
                                             info.Value.parameter.Type);
                }
                localParset.Save();
                //m_cmdList.Clear();
                if (isSaveAs)
                {
                    ClearAll();
                }
            }
            catch (IOException exception)
            {
                MessageBox.Show(exception.Message);
            }
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog dlg = new SaveFileDialog())
            {
                dlg.CheckPathExists = true;
                dlg.ValidateNames = true;
                dlg.DefaultExt = XmlExt;
                dlg.Filter = "XML files (*" + XmlExt + ")|*" + XmlExt;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    if (dlg.FileName.EndsWith(XmlExt))
                    {
                        SaveParams(dlg.FileName, true);
                    }
                    else
                    {
                        MessageBox.Show(Resources.MAIN_InvalidFileExtText, Resources.MAIN_InvalidFileExtTitle,
                                        MessageBoxButtons.OK);
                    }
                }
            }
        }
    }
}
